<template>
  <div style="color: red">call apply bind的使用</div>
  <br />
  <div>1、三者都可以改变函数的this对象指向。</div>
  <div>
    2、三者第一个参数都是this要指向的对象，如果如果没有这个参数或参数为undefined或null，则默认指向全局window。
  </div>
  <div>
    3、三者都可以传参，但是apply是数组，而call是参数列表，且apply和call是一次性传入参数，而bind可以分为多次传入。
    bind 是返回绑定this之后的函数，便于稍后调用；apply 、call 则是立即执行 。
  </div>
</template>

<script setup lang="ts" name="Hoisting">
const obj = {
  name: "Jack",
  say: function (age: any = 25, school: string) {
    console.log(`大家好我叫：${this.name},今年${age}岁了,在${school}上学`);
  },
};

const obj2 = {
  name: "Tom",
};

// obj.say.call(obj2, 25, "理工"); //参数列表
// obj.say.apply(obj2, [26, "广州"]); //数组
const res = obj.say.bind(obj2); //返回一个函数还需要再次调用并传参

// res(25, "广东");

const man = {
  name: "Quina",
  age: 30,
  getName: function () {
    console.log(this.name); //Quina
  },
  getAge: function () {
    function aa() {
      //局部函数
      console.log("1", this); //undefined
      // console.log("1", this.age);
    }
    aa();
    console.log("2", this); //{name: 'Quina', age: 30, getName: ƒ, getAge: ƒ}
    console.log("2", this.age); //30
  },
};

// man.getAge();

// 1.手写call方法
// 因为call方法是函数上的方法,所以可以直接在函数的构造函数上添加sqCall的方法
(Function.prototype as any).sqCall = function (ctx: any, ...args: any) {
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx);
  const key = Symbol("temp"); //永远不会重复的属性名
  Object.defineProperty(ctx, key, {
    enumerable: false,
    value: this, //这里的this指向调用sqCall方法的函数
    configurable: true,
  });

  const result = ctx[key](...args); //执行这个函数并传入参数 会得到一个值
  delete ctx[key]; //删除临时存进去的temp属性名
  return result;
};

const obj5 = {
  name: "sq",
  age: 25,
};

const obj6 = {
  name: "123",
  sayName(hobby: string, age: number) {
    console.log(`我是${this.name},我的爱好是${hobby},今年${age}岁了`, this);
    return hobby;
  },
};

// const ress = (obj6.sayName as any).sqCall(obj5, "网球",55);
// console.log(ress);
// (obj6.sayName as any).sqCall(obj5, "111");

// 2.手写apply
(Function.prototype as any).sqApplay = function (ctx: any, arr?: any[]) {
  ctx = ctx == null || ctx === undefined ? globalThis : Object(ctx);
  const key = Symbol("temp");
  Object.defineProperty(ctx, key, {
    enumerable: false,
    value: this,
    configurable: true,
  });

  if (!arr) {
    return ctx[key]();
  }
  const result = ctx[key](...arr);
  delete ctx[key];
  return result;
};

const obj7 = {
  name: "sq",
  age: 25,
};

const obj9 = {
  name: "sq11",
  age: 25,
};
const obj8 = {
  name: "123",
  sayName(hobby?: string, age?: number) {
    console.log(`我是${this.name},我的爱好是${hobby},今年${age}岁了`, this);
    return hobby;
  },
};

(obj8.sayName as any).sqApplay(obj9,['网球',25]);
</script>

<style scoped lang="scss"></style>
